﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Data;
using System.ComponentModel;

namespace CFR.Silverlight.Scheduling
{
    public class DayView : ViewBase
    {
        bool _templateApplied = false;

        internal DayViewColumnPresenter ColumnPresenter { get; private set; }
        protected internal Canvas EventsCanvas { get; private set; }
        protected internal HourPanel HoursPanel { get; private set; }
        protected internal ScrollViewer Scroller { get; private set; }

        private double _lineHeight = 30;

        public double LineHeight
        {
            get { return _lineHeight; }
            set { _lineHeight = value; }
        }


        public double ColumnWidth
        {
            get
            {
                return (ActualWidth - 55) / (double)Dates.Count;
            }
        }

        public SelectedDatesCollection Dates { get { return Scheduler.Calendar.SelectedDates; } }

        public DayView() { }

        public DayView(Scheduler scheduler)
            : base(scheduler)
        {
            this.DefaultStyleKey = typeof(DayView);
            this.UseLayoutRounding = false;
            this.Loaded += new RoutedEventHandler(DayView_Loaded);
            this.SizeChanged += new SizeChangedEventHandler(DayView_SizeChanged);
        }

        void DayView_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            RefreshEvents();
        }

        void DayView_Loaded(object sender, RoutedEventArgs e)
        {
            ApplyTemplate();
            //Refresh();
        }
        private void SetScroller()
        {
            if (Scheduler.Events.Count > 0 && Scroller.VerticalOffset == 0 && !_dragging)
            {
                var minHour = Scheduler.Events.Where(e => !e.IsAllDayEvent && e.Calendar.IsShownInScheduler).Min(e => e.StartDate.Hour);

                var scrollPosition = ((Scroller.ScrollableHeight / 24) * minHour);
                Scroller.ScrollToVerticalOffset(scrollPosition);
            }
        }

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();

            HoursPanel = (HourPanel)GetTemplateChild("HoursPanel");

            ColumnPresenter = (DayViewColumnPresenter)GetTemplateChild("ColumnPresenter");
            ColumnPresenter.ParentDayView = this;
            ColumnPresenter.Refresh();

            EventsCanvas = (Canvas)GetTemplateChild("EventsCanvas");
            EventsCanvas.MouseMove += new MouseEventHandler(EventsCanvas_MouseMove);
            EventsCanvas.MouseLeftButtonDown += new MouseButtonEventHandler(EventsCanvas_MouseLeftButtonDown);

            EventsCanvas.AddHandler(UIElement.MouseLeftButtonUpEvent, new MouseButtonEventHandler(HandleBorder_MouseLeftButtonUp), true);


            Scroller = (ScrollViewer)GetTemplateChild("Scroller");

        }

        void EventsCanvas_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            var elements = VisualTreeHelper.FindElementsInHostCoordinates(e.GetPosition(null), EventsCanvas);

            if (elements.OfType<EventItem>().Count() > 0)
                return;

            EventItem ei = new EventItem(this);
            var p = e.GetPosition(EventsCanvas);

            var start = ConvertPointToDateTime(p);
            var end = start.AddMinutes(30);

            ei.Event = new Event()
            {
                Calendar = Scheduler.Calendars.ElementAt(0),
                StartDate = start,
                EndDate = end,
                IsAllDayEvent = false

            };
            var ee = new EventItemCreateEventArgs(ei, (ss, eee) =>
            {
                if (!eee.Cancel)
                {
                    Scheduler.Events.Add(eee.Item.Event);
                    RefreshEvents();
                }
            });

            Scheduler.RaiseCreatingEventItem(ee);

        }


        public void RefreshEvents()
        {
            if (EventsCanvas == null)
                return;


            EventsCanvas.Children.Clear();

            DateTime minDate;
            DateTime maxDate;

            if (Dates.Count == 0)
                Scheduler.UpdateCalendarSelectedDates();
         
            minDate = Dates.Min().Date;
            maxDate = Dates.Max().Date;

             
            var dayWidth = Math.Max(0, ((ActualWidth - 55) / (double)Dates.Count));
         

            foreach (Event ee in Scheduler.Events.Where(eee => eee.Calendar.IsShownInScheduler))
            {

                if (!ee.IsAllDayEvent)
                {
                    if (((ee.StartDate >= minDate && ee.StartDate <= maxDate.AddDays(1)) || (ee.EndDate >= minDate && ee.EndDate <= maxDate.AddDays(1))))
                    {
                        var top = HoursPanel.GetTimeYOffset(ee.StartDate);
                        var bottom = HoursPanel.GetTimeYOffset(ee.EndDate);

                        EventItem ei = new EventItem(this)
                        {
                            Event = ee,
                            Background = ee.Calendar.Background,
                            Title = ee.Name,
                            Foreground = new SolidColorBrush(Colors.White),
                            Width = Math.Max(dayWidth - 10d, 0),
                            Height = Math.Max(bottom - top, 15),
                            TitleContentTemplate = Scheduler.EventTitleContentTemplate
                        };

                        if (Scheduler.EventTooltip != null)
                            ToolTipService.SetToolTip(ei, new ContentControl() { Content = ee, ContentTemplate = Scheduler.EventTooltip });

                        ei.HandleLeftMouseButtonDown += new MouseButtonEventHandler(event_HandleLeftMouseButtonDown);
                        //ei.HandleBorder.MouseLeftButtonUp += new MouseButtonEventHandler(HandleBorder_MouseLeftButtonUp);

                        var peers = Scheduler.Events.Where(p => p.Calendar.IsShownInScheduler && p.StartDate.Date == ee.StartDate.Date
                            && (
                            (p.StartDate == ee.StartDate && p.EndDate == ee.EndDate)
                            || (p.StartDate >= ee.StartDate && p.StartDate < ee.EndDate)
                            || (p.EndDate > ee.StartDate && p.EndDate <= ee.EndDate)
                            || (p.StartDate > ee.StartDate && p.EndDate < ee.EndDate)
                            || (p.StartDate < ee.StartDate && p.EndDate > ee.EndDate)
                            )
                            ).OrderByDescending(p => p.Duration.TotalMilliseconds);

                        double peerOffset = peers.ToList().IndexOf(ee);
                        double peerCount = peers.Count() ;

                        if (peerCount == 2)
                        {                   
                            ei.Width /= 2d;
                        }
                        else if (peerCount > 1)
                        {
                            var nonSelf = peers.Where(p => p.Guid != ee.Guid);
                            var max = 0d;
                            foreach (var non in nonSelf)
                            {
                                max = Math.Max(max, nonSelf.Count(p =>
                                {
                                    return (non.StartDate >= p.StartDate && non.StartDate < p.EndDate)
                                         || (non.EndDate > p.StartDate && non.EndDate <= p.EndDate)
                                         || (non.StartDate > p.StartDate && non.EndDate < p.EndDate)
                                         || (non.StartDate < p.StartDate && non.EndDate > p.EndDate);
                                        
                                }));
                            }
                            peerOffset = Math.Min(peerOffset, max );
                            ei.Width /= max+1d;
                        }


                        var left = ((ee.StartDate.Date - Dates.Min().Date).Days * dayWidth) + (peerOffset * ei.Width) + 3;

                        Canvas.SetTop(ei, top);
                        Canvas.SetLeft(ei, left);

                        EventsCanvas.Children.Add(ei);
                    }
                }
            }
            if (!_dragging)
                SetScroller();
        }


        private bool _dragging = false;
        private Point _lastPoint;
        private EventItem _event = null;
        void HandleBorder_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            if (_dragging)
            {
                _dragging = false;
                _event.IsDragging = false;

                Scheduler.RaiseEventItemMoved(new EventItemEventArgs(_event));
                RefreshEvents();
                _event = null;
            }
        }
        void event_HandleLeftMouseButtonDown(object sender, MouseButtonEventArgs e)
        {
            _dragging = true;
            _event = sender as EventItem;
            _event.IsDragging = true;
            _lastPoint = e.GetPosition(EventsCanvas);
        }
        private DateTime ConvertPointToDateTime(Point p)
        {
            var currentLine = GetLineIndexFromYPosition(p.Y);

            var currentColumn = GetColumnIndexFromXPosition(p.X);


            return Dates[currentColumn].Date.AddMinutes(currentLine * 30);
        }
        private int GetLineIndexFromYPosition(double y)
        {
            var currentLine = (int)Math.Floor(y / LineHeight);

            return currentLine;
        }
        private int GetColumnIndexFromXPosition(double x)
        {
            var currentColumn = (int)Math.Floor(x / ColumnWidth);

            return currentColumn;
        }
        void EventsCanvas_MouseMove(object sender, MouseEventArgs e)
        {
            if (_dragging)
            {
                var left = Canvas.GetLeft(_event);
                var top = Canvas.GetTop(_event);
                var p = e.GetPosition(EventsCanvas);

                var dt = ConvertPointToDateTime(p);

                //Get the Timespan of the dragged item
                var duration = _event.Event.EndDate - _event.Event.StartDate;

                DateTime startTime = dt;
                DateTime endTime = startTime.Add(duration);

                if (startTime != _event.Event.StartDate && endTime != _event.Event.EndDate)
                {

                    EventItemMovingEventArgs ee = new EventItemMovingEventArgs(_event)
                    {
                        NewStartDate = startTime,
                        NewEndDate = endTime,
                        Cancel = false
                    };

                    Scheduler.RaiseEventItemMoving(ee);

                    if (!ee.Cancel)
                    {

                        //Set the position of the dragged EventItem
                        Canvas.SetLeft(_event, GetColumnIndexFromXPosition(p.X) * ColumnWidth + 2);
                        Canvas.SetTop(_event, GetLineIndexFromYPosition(p.Y) * LineHeight);

                        //Set the new times for the dragged item
                        _event.Event.StartDate = ee.NewStartDate;
                        _event.Event.EndDate = ee.NewEndDate;

                        RefreshEvents();
                    }
                }

                _lastPoint = p;
            }
        }

        protected internal override void Refresh()
        {

            base.Refresh();

            if (ColumnPresenter != null)
                ColumnPresenter.Refresh();

            RefreshEvents();
        }
    }
}
